package edu.moravian.CollisionPhysics;

import edu.moravian.entity.BallEntity;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
import org.junit.Test;

   


/**
 *
 * @author ronaghan
 */
public class TwoEntityCollisionEngineTest
{
    
    //The base path for all of our collision engine tests
    private static final String BASE_PATH = "resources/test/edu/moravian/EntityCollisionEngine";
    
    
    /**
     * Test that two objects that will not be close
     * enough to collide even if they were headed straight towards
     * each other are not detected as colliding
     */
    @Test
    public void testNotCloseEnoughFail()
    {
        String relativePath = "WillNotCollide/Proximity";
        File path = new File(BASE_PATH, relativePath);          
        
        for(BallLoader balls: getBallLoaders(path))
        {
            EntityCollisionEngine collisionEngine = new EntityCollisionEngine(balls.getElasticity());
            
            if(collisionEngine.willCollide(balls.getBallOne(), balls.getBallTwo(), balls.getDelta()))
            {
                fail("Expected that balls would not collide for file: " + balls.getFilePath().toString());
            }
        }
    }
    
    
    
    /**
     * Test that two entities that are not heading towards
     * each other will not be detected as colliding 
     */
    @Test
    public void testNotHeadingTowardsEachOther()
    {
        String relativePath = "WillNotCollide/Heading";
        File path = new File(BASE_PATH, relativePath);
        
        for(BallLoader balls: getBallLoaders(path))
        {
            EntityCollisionEngine collisionEngine = new EntityCollisionEngine(balls.getElasticity());
            
            if(collisionEngine.willCollide(balls.getBallOne(), balls.getBallTwo(), balls.getDelta()))
            {
                fail("Expected that balls would not collide for file: " + balls.getFilePath().toString());
            }
        }
    }

    
    
    /**
     * Test that two entities that will fly by each other 
     * will not be detected as colliding
     */
    @Test
    public void testFlyBy()
    {
        String relativePath = "WillNotCollide/FlyBy";
        File path = new File(BASE_PATH, relativePath);
        
        for(BallLoader balls: getBallLoaders(path))
        {
            EntityCollisionEngine collisionEngine = new EntityCollisionEngine(balls.getElasticity());
            
            if(collisionEngine.willCollide(balls.getBallOne(), balls.getBallTwo(), balls.getDelta()))
            {
                fail("Expected that balls would not collide for file: " + balls.getFilePath().toString());
            }        
        }
    }
    
    
    
    /**
     * Test that two objects that are traveling fast enough 
     * to collide, are heading towards each other, and not going 
     * to fly by but are not going to collide in the given delta 
     * (They will collide shortly after the given delta) will not 
     * be detected as colliding 
     */
    @Test
    public void testCollisionNextFrame()
    {
        String relativePath = "WillNotCollide/NextFrame";
        File path = new File(BASE_PATH, relativePath);

        for(BallLoader balls: getBallLoaders(path))
        {
            EntityCollisionEngine collisionEngine = new EntityCollisionEngine(balls.getElasticity());
            
            if(collisionEngine.willCollide(balls.getBallOne(), balls.getBallTwo(), balls.getDelta()))
            {
                fail("Expected that balls would not collide for file: " + balls.getFilePath().toString());
            }
        }
    }
    
    /**
     * Test that balls that should collide, will be detected as colliding
     */
    @Test
    public void testWillCollide()
    {
        String relativePath = "WillCollide";
        File path = new File(BASE_PATH, relativePath);

        for(BallLoader balls: getBallLoaders(path))
        {
            EntityCollisionEngine collisionEngine = new EntityCollisionEngine(balls.getElasticity());

            if(collisionEngine.willCollide(balls.getBallOne(), balls.getBallTwo(), balls.getDelta()) == false)
            {
                fail("Expected that balls would collide for file: " + balls.getFilePath().toString());
            }
        }
    }
    
    
    
    @Test
    public void testCollisionResponse()
    {
        String relativeBeforePath = "CollisionResponse/Before";
        String relativeAfterPath = "CollisionResponse/After";
        
        File beforeFile = new File(BASE_PATH, relativeBeforePath);
        File afterFile = new File(BASE_PATH, relativeAfterPath);
        
        List<BallLoader> before = getBallLoaders(beforeFile);
        List<BallLoader> after = getBallLoaders(afterFile);
        
        for(int i=0; i<before.size(); i++)
        {
            EntityCollisionEngine collisionEngine = new EntityCollisionEngine(before.get(i).getElasticity());
            
            BallEntity beforeOne = before.get(i).getBallOne();
            BallEntity beforeTwo = before.get(i).getBallTwo();
            
            collisionEngine.collisionResponse(beforeOne, beforeTwo);
            
            BallEntity afterOne = after.get(i).getBallOne();
            BallEntity afterTwo = after.get(i).getBallTwo();
            
            
            if(beforeOne.getVelocity().equals(afterOne.getVelocity()) == false)
            {
                fail("Velocities of ball one were not the same for " + 
                        before.get(i).getFilePath().toString() + " and " + after.get(i).getFilePath().toString());
            }
            
            if(beforeTwo.getVelocity().equals(afterTwo.getVelocity()) == false)
            {
                fail("Velocities of ball two were not the same for " + 
                        before.get(i).getFilePath().toString() + " and " + after.get(i).getFilePath().toString());
            }
            
            if(beforeOne.getLocation().equals(afterOne.getLocation()) == false)
            {
                System.out.println("one location: " + beforeOne.getLocation());
                
                fail("Locations of ball one were not the same for " + 
                        before.get(i).getFilePath().toString() + " and " + after.get(i).getFilePath().toString());
            }
            
            if(beforeTwo.getLocation().equals(afterTwo.getLocation()) == false)
            {
                fail("Locations of ball two were not the same for " + 
                        before.get(i).getFilePath().toString() + " and " + after.get(i).getFilePath().toString());
            }
        }
        
    }
    
    
    /**
     * A helper method to create ball loaders for each file in a given path
     * 
     * @param file the abstract path to check 
     * 
     * @return a list of ball loaders, one for each file 
     */
    public List<BallLoader> getBallLoaders(File path)
    {
        List<BallLoader> ballLoaders = new ArrayList<BallLoader>();
        
        //make sure our current directory is a directory and not a file
        if(path.isDirectory() == false)
        {
            fail("The specified path is not a directory. " + path.toString());
        }
        
        //for every file in our current path
        for(File file: path.listFiles())
        {
            //make sure it is actually a file and we can read it 
            if(file.isFile() == false  && file.canRead() == false)
            {
               fail("Could not read the current file or it wasn't actually a file: " + file.toString());
            }
            
            try
            {
                BallLoader ballLoader = new BallLoader(file);
                ballLoaders.add(ballLoader);
            }
            catch (FileNotFoundException ex)
            {
                fail("Could not find the file " + file.toString() + ".\n  "
                        + ex.toString());
            }
            catch (IOException ex)
            {
                fail("IOException for file " + file.toString() + ".\n  "
                        + ex.toString());
            }
            catch(Exception ex)
            {
                fail("General Exception for file " + file.toString() + ".\n  " 
                        + ex.toString());
            }
            
        }
        
        //make sure the directory acually had some files to test in it s
        if(ballLoaders.isEmpty())
        {
            fail("There were no files to load for the directory: " + path.toString());
        }
        
        return ballLoaders;
    }
    
    
    
    
   

   
    



}



